﻿using Core.Framework;
using Grain.Interfaces;
using Orleans;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace Grain.Implements
{
    public class SystemObjectChannel
    {
        public string key { get; set; }
        public string parameter { get; set; }
    }

    public class SystemObject
    {
        public SystemObject(object state)
        {
            this.State = state;
        }
        public SystemObjectChannel Channel { get; set; }
        public string Sesstion { get; set; }
        public List<object> notifys { get => new List<object>(); }
        public object State { get; set; }
    }

    public class CloudRunningFunctionExtend
    {
        readonly IGrainFactory factory;
        public CloudRunningFunctionExtend(IGrainFactory factory)
        {
            this.factory = factory;
        }


        /// <summary>
        /// 获取函数执行参数
        /// </summary>
        /// <returns></returns>
        public object[] GetFunctionParameters(object[] parameters)
        {
            object systemObejct = this.GetSystemObejct();

            object[] args = this.CreateParameters(systemObejct, parameters);

            return args;
        }

        public async Task<object[]> GetFunctionParametersAsync(string channel, object[] parameters)
        {
            object systemObejct = await this.GetSystemObejctAsync(channel);

            object[] args = this.CreateParameters(systemObejct, parameters);

            return args;
        }

        /// <summary>
        /// 获取函数执行参数
        /// </summary>
        /// <returns></returns>
        public object[] GetFunctionParametersContainState(object state, object[] parameters)
        {
            object systemObejct = this.GetSystemObejct(state);

            object[] args = this.CreateParameters(systemObejct, parameters);

            return args;
        }

        public async Task<object[]> GetFunctionParametersContainStateAsync(object state, string channel, object[] parameters)
        {
            object systemObejct = await this.GetSystemObejctAsync(channel, state);

            object[] args = this.CreateParameters(systemObejct, parameters);

            return args;
        }




        public async Task InvokeEndAsync(bool isHavChannel, string channel, FunctionResult<dynamic> result)
        {
            if (result.IsFinished)
            {
                // 检查通知信息
                await this.CheckNotifyAsync((string)result.Data.notifys);

                if (isHavChannel)
                {
                    IChannelService channelService = this.factory.GetGrain<IChannelService>(channel);

                    // 用户退出 或者 切换用户
                    this.CheckChannelOutLoginOrSwitchChannel(result, channel);

                    // 用户退出
                    if (string.IsNullOrWhiteSpace(result.Channel) & result.IsChangeChannel)
                    {
                        // clear sesstion
                        await channelService.SetChannelSesstion(string.Empty);
                    }

                    // 切换用户
                    else if (result.IsChangeChannel)
                    {
                        // clear sesstion
                        await channelService.SetChannelSesstion(string.Empty);

                        // 切换service
                        channelService = this.factory.GetGrain<IChannelService>(result.Channel);

                        // check sesstion
                        string sesstion = result.Data.sesstion.ToString();
                        if (!string.IsNullOrWhiteSpace(sesstion))
                        {
                            await channelService.SetChannelSesstion(sesstion);
                        }

                        // check parameter
                        string parameter = result.Data.channel.parameter.ToString();
                        if (!string.IsNullOrWhiteSpace(parameter))
                        {
                            await channelService.SetChannelInfo(parameter);
                        }
                    }

                    // 用户未发生变化
                    else
                    {
                        // 更新条件：sesstion 不为空并且发生变化
                        string sesstion = result.Data.sesstion.ToString();
                        if (!string.IsNullOrWhiteSpace(sesstion) & result.ChannelSession != sesstion)
                        {
                            await channelService.SetChannelSesstion(sesstion);
                        }

                        // 更新条件：parameter 不为空并且发生变化
                        string parameter = result.Data.channel.parameter.ToString();
                        if (!string.IsNullOrWhiteSpace(parameter) & result.ChannelParameter != parameter)
                        {
                            await channelService.SetChannelInfo(parameter);
                        }
                    }
                }
                else if (!string.IsNullOrWhiteSpace((string)result.Data.channel.key))
                {
                    result.Channel = (string)result.Data.channel.key;
                    IChannelService channelService = this.factory.GetGrain<IChannelService>(result.Channel);

                    string sesstion = result.Data.sesstion?.ToString();
                    if (!string.IsNullOrWhiteSpace(sesstion))
                    {
                        await channelService.SetChannelSesstion(sesstion);
                    }

                    string parameter = result.Data.channel.parameter?.ToString();
                    if (!string.IsNullOrWhiteSpace(parameter))
                    {
                        await channelService.SetChannelInfo(parameter);
                    }
                }

                result.Debug = result.Data.debugs;
                result.IsWriteState = (bool)result.Data.isWriteState;
                result.State = result.Data.state;
                result.Data = result.Data.result;
            }
        }


        public FunctionResult<dynamic> GetFunctionResult(
            TimeSpan ts1,
            SystemObject system,
            MethodResult<dynamic> resultJS)
        {
            FunctionResult<dynamic> result = this.IniFunctionResult(system);
            result.IsFinished = resultJS.IsFinished;
            result.Data = resultJS.Data;
            result.Debug = resultJS.Debug;
            result.Discription = resultJS.Discription;
            TimeSpan ts2 = new TimeSpan(DateTime.Now.Ticks);
            result.RunTimeTotalMilliseconds = ts2.Subtract(ts1).TotalMilliseconds;
            return result;
        }



        /// <summary>
        /// 获取系统对象
        /// </summary>
        /// <returns></returns>
        private SystemObject GetSystemObejct(object state = null) => new SystemObject(state);

        private async Task<SystemObject> GetSystemObejctAsync(string channel, object state = null)
        {

            IChannelService channelService = this.factory.GetGrain<IChannelService>(channel);

            string channelInfo = await channelService.GetChannelInfo();
            string sesstionInfo = await channelService.GetChannelSesstion();

            return new SystemObject(state)
            {
                Channel = new SystemObjectChannel
                {
                    key = channel,
                    parameter = channelInfo
                },
                Sesstion = sesstionInfo
            };
        }

        private object[] CreateParameters(object systemObejct, object[] parameters)
        {
            object[] args = new object[parameters.Length + 1];

            if (parameters.Length > 0)
            {
                for (int i = 0; i < args.Length; i++)
                {
                    args[i] = i == 0 ? systemObejct : parameters[i - 1];
                }
            }
            else
                args = new object[] { systemObejct };

            return args;
        }

        private FunctionResult<dynamic> IniFunctionResult(SystemObject system)
        {
            return new FunctionResult<dynamic>()
            {
                ChannelParameter = system.Channel?.parameter,
                ChannelSession = system.Sesstion
            };
        }

        private async Task CheckNotifyAsync(string notifys)
        {
            // 如果通知信息不为空，则触发通知事件
            if (!string.IsNullOrWhiteSpace(notifys))
            {
                var notifyList = notifys.TryToList<NotifyHandler.NotifyEntity>();
                var handler = new NotifyHandler(notifyList);
                await handler.WorkingAsync(this.factory);
            }
        }

        private void CheckChannelOutLoginOrSwitchChannel(FunctionResult<dynamic> result, string oldChannel)
        {
            string key = (string)result.Data.channel.key;
            if (string.IsNullOrWhiteSpace(key) || !key.Equals(oldChannel))
            {
                result.Channel = key;
                result.IsChangeChannel = true;
            }
        }
    }
}
